#include <stdio.h>
#include "csapp.h"

/* 推荐的最大缓存和对象大小 */
#define MAX_CACHE_SIZE 1049000
#define MAX_OBJECT_SIZE 102400
#define MAX_CACHE 10
 
/* 你不会因包含这一行长代码而失分 */
static const char *user_agent_hdr = "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.3) Gecko/20120305 Firefox/10.0.3\r\n";

void handle_request(int client_fd);
int parse_url(char *url, char *host, char *path, char *port, char *request_header);
void read_request_headers(rio_t *rp, int server_fd);
void send_content_to_client(int server_fd, int client_fd, char *url);
void *client_thread(void *vargp);
int fn1(int x);
int fn2(int x);
int get_max_lru_cache();

/* 读写锁结构 */
struct RWLock {
    sem_t mutex;         // 基本锁
    sem_t write_lock;    // 写锁
    int read_count;      // 读者数量
};

/* LRU缓存结构 */
struct Cache {
    int lru_value;              // 引用计数，值越大表示最近使用
    char url[MAXLINE];          // 唯一标识内容的URL
    char content[MAX_OBJECT_SIZE];
};

struct Cache cache[MAX_CACHE];  // 缓存，最大为MAX_CACHE条目
struct RWLock* rw_lock;        // 读写锁指针

void initialize_rwlock();        // 初始化读写锁
char *read_from_cache(char *url);    // 从缓存读取
void write_to_cache(char *content, char *url);  // 写入缓存

int main(int argc, char **argv)
{
    int listen_fd;
    int *client_fd;        /* 使用指针，避免竞争条件 */
    char host[MAXLINE], port[MAXLINE];
    socklen_t client_len;
    struct sockaddr_storage client_addr;
    pthread_t tid;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s <port>\n", argv[0]);
        exit(1);
    }

    rw_lock = Malloc(sizeof(struct RWLock));
    initialize_rwlock();

    /* 设置监听套接字，准备接收连接 */
    listen_fd = Open_listenfd(argv[1]);
    while (1) {
        client_len = sizeof(client_addr);

        client_fd = Malloc(sizeof(int));

        /* 等待客户端连接 */
        *client_fd = Accept(listen_fd, (SA *)&client_addr, &client_len);

        /* 获取客户端地址 */
        Getnameinfo((SA *)&client_addr, client_len, host, MAXLINE, port, MAXLINE, 0);
        printf("Accepted connection from (%s, %s)\n", host, port);
        /* 在这里加入调用 fn1 和 fn2 */
        int test_value = 10;
        int result_fn1 = fn1(test_value);
        int result_fn2 = fn2(test_value);
        /* 创建一个新线程来处理客户端请求 */
        Pthread_create(&tid, NULL, client_thread, client_fd);
    }
}

void *client_thread(void *vargp)
{
    int client_fd = *((int *)vargp);
    Pthread_detach(pthread_self());
    Free(vargp);
    handle_request(client_fd);
    Close(client_fd);
    return NULL;
}

/* 处理客户端HTTP请求 */
void handle_request(int client_fd)
{
    char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
    char host[MAXLINE], path[MAXLINE], port[MAXLINE], request_header[MAXLINE];
    int server_fd;
    rio_t rio;

    /* 读取请求行和头部信息 */
    Rio_readinitb(&rio, client_fd);
    Rio_readlineb(&rio, buf, MAXLINE);
    sscanf(buf, "%s %s %s", method, uri, version);
    if (strcasecmp(method, "GET")) {
        printf("Method not implemented\n");
        return;
    }

    char *cached_content = read_from_cache(uri);
    if (cached_content != NULL) {
        Rio_writen(client_fd, cached_content, strlen(cached_content));
        free(cached_content);
    } else {
        /* 解析URL，提取主机名、路径和端口 */
        parse_url(uri, host, path, port, request_header);

        /* 建立与服务器的连接 */
        server_fd = Open_clientfd(host, port);

        /* 向服务器发送请求头 */
        Rio_writen(server_fd, request_header, strlen(request_header));
        read_request_headers(&rio, server_fd);

        /* 从服务器获取内容并发送给客户端 */
        send_content_to_client(server_fd, client_fd, uri);
    }
}

/* 解析URI，提取主机名、路径、端口，并生成请求头 */
int parse_url(char *url, char *host, char *path, char *port, char *request_header)
{
    sprintf(port, "80");  // 默认端口

    char *end, *bp;
    char *tail = url + strlen(url);  // URL的最后一个字符

    char *bg = strstr(url, "//");

    bg = (bg != NULL ? bg + 2 : url);  // 主机名的起始位置

    end = bg;  // 主机名的结束位置
    while (*end != '/' && *end != ':') end++;
    strncpy(host, bg, end - bg);

    bp = end + 1;  // 端口的起始位置
    if (*end == ':') {  // 如果指定了端口
        end++;
        bp = strstr(bg, "/");  // 端口的结束位置

        strncpy(port, end, bp - end);  
        end = bp;  // 路径的起始位置
    }
    strncpy(path, end, (int)(tail - end) + 1);

    /* 请求行：GET /hub/index.html HTTP/1.0 */
    sprintf(request_header, "GET %s HTTP/1.0\r\nHost: %s\r\n", path, host);
    
    return 1;
}

/* 读取HTTP请求头部 */
void read_request_headers(rio_t *rp, int server_fd)
{
    char buf[MAXLINE];

    sprintf(buf, "%s", user_agent_hdr);
    Rio_writen(server_fd, buf, strlen(buf));
    sprintf(buf, "Connection: close\r\n");
    Rio_writen(server_fd, buf, strlen(buf));
    sprintf(buf, "Proxy-Connection: close\r\n");
    Rio_writen(server_fd, buf, strlen(buf));

    /* 转发其他请求头 */
    for (Rio_readlineb(rp, buf, MAXLINE); strcmp(buf, "\r\n"); Rio_readlineb(rp, buf, MAXLINE)) {
        if (strncmp("Host", buf, 4) == 0 || strncmp("User-Agent", buf, 10) == 0
            || strncmp("Connection", buf, 10) == 0 || strncmp("Proxy-Connection", buf, 16) == 0)
            continue;
        printf("%s", buf);
        Rio_writen(server_fd, buf, strlen(buf));
    }
    Rio_writen(server_fd, buf, strlen(buf));
}

/* 从服务器发送内容到客户端 */
void send_content_to_client(int server_fd, int client_fd, char *uri)
{
    size_t n, size = 0;
    char buf[MAXLINE], content[MAX_OBJECT_SIZE];
    rio_t srio;

    Rio_readinitb(&srio, server_fd);
    while ((n = Rio_readlineb(&srio, buf, MAXLINE)) != 0) {
        Rio_writen(client_fd, buf, n);

        if (n + size <= MAX_OBJECT_SIZE) {
            sprintf(content + size, "%s", buf);
            size += n;
        } else {
            size = MAX_OBJECT_SIZE + 1;
        }
    }

    write_to_cache(content, uri);
}

/*-----缓存部分开始-----*/
void initialize_rwlock()
{
    rw_lock->read_count = 0;
    sem_init(&rw_lock->mutex, 0, 1);
    sem_init(&rw_lock->write_lock, 0, 1);
}

void write_to_cache(char *content, char *url)
{
    sem_wait(&rw_lock->write_lock);  // 等待写锁
    int index;
    /* 检查缓存中是否有空位 */
    for (index = 0; index < MAX_CACHE; index++) {
        if (cache[index].lru_value == 0) {
            break;
        }
    }

    /* 如果没有空位，应用LRU驱逐策略 */
    if (index == MAX_CACHE) {
        int min_lru = cache[0].lru_value;

        /* 查找最久未使用的缓存 */
        int i;
        for (i = 1; i < MAX_CACHE; i++) {
            if (cache[i].lru_value < min_lru) {
                min_lru = cache[i].lru_value;
                index = i;
            }
        }
    }

    cache[index].lru_value = get_max_lru_cache() + 1;
    strcpy(cache[index].url, url);
    strcpy(cache[index].content, content);
    sem_post(&rw_lock->write_lock);  // 释放锁
}

char *read_from_cache(char *url)
{
    sem_wait(&rw_lock->mutex);  // 等待并获取锁
    if (rw_lock->read_count == 1)
        sem_wait(&rw_lock->write_lock);  // 读者阻塞写者
    rw_lock->read_count++;
    sem_post(&rw_lock->mutex);  // 释放锁

    char *content = NULL;
    int i;
    for (i = 0; i < MAX_CACHE; i++) {
        /* 缓存命中 */
        if (strcmp(url, cache[i].url) == 0) {
            content = (char *)Malloc(strlen(cache[i].content));
            strcpy(content, cache[i].content);
            int max_lru = get_max_lru_cache();  // 获取最高的LRU值
            cache[i].lru_value = max_lru + 1;  // 增加LRU
            break;
        }
    }

    sem_wait(&rw_lock->mutex);  // 等待并获取锁
    rw_lock->read_count--;
    if (rw_lock->read_count == 0)  // 没有更多的读者，释放写锁
        sem_post(&rw_lock->write_lock);
    sem_post(&rw_lock->mutex);  // 释放锁
    return content;
}

int fn1(int x){
    if(x != 0) return x;
    else return 0;
}

int fn2(int x){
    x = fn1(x);
    if (x != 0) return x;
    else return 0;
}

int get_max_lru_cache()
{
    int i;
    int max = 0;
    for (i = 0; i < MAX_CACHE; i++) {
        if (cache[i].lru_value > max) {
            max = cache[i].lru_value;
        }
    }
    return max;
}
/*-----缓存部分结束-----*/
